﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using static TorchSharp.torch.nn;

namespace NgpSharp
{
    public class DLLLoader
    {
        private static readonly object SyncRoot = new object();
        internal static bool IsInit { get; private set; } = false;

        static DLLLoader()
        {
            Init();
        }

        internal static void Init()
        {
            if (IsInit) return;
            lock (SyncRoot)
            {
                if (IsInit) return;
                NativeLibrary.SetDllImportResolver(typeof(HashEncoderLoader).Assembly, ImportResolver);
                IsInit = true;
            }
        }

        private static IntPtr ImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
        {
            var path = GetPath(libraryName, assembly);
            if (!File.Exists(path)) throw new FileNotFoundException($"cannot found library with name {libraryName}");
            IntPtr h = NativeLibrary.Load(path);
            return h;
        }

        private static string GetPath(string libraryName, Assembly assembly)
        {
            if (string.IsNullOrEmpty(libraryName)) throw new ArgumentNullException(nameof(libraryName));
            if (assembly == null) throw new ArgumentNullException(nameof(assembly));
#pragma warning disable IL3000
            string location = assembly.Location;
#pragma warning restore IL3000
            string rootPath = Path.GetDirectoryName(location) ?? throw new DllNotFoundException($"cannot load dll with path {location}");
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                return Path.Combine(rootPath, "runtimes", "win-x64", "native", $"{libraryName}.dll");
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                return Path.Combine(rootPath, "runtimes", "linux-x64", "native", $"lib{libraryName}.so");
            }
            else throw new NotSupportedException("Not supported form current system");
        }
    }
}
